/*
 * MIT License
 *
 * Copyright (c) 2019 Mr.css
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

package com.wendy.common.core.utils.reflect;


import com.wendy.common.core.utils.CommonUtils;

import java.lang.reflect.*;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 主要用于对象解析
 *
 * @author Mr.css
 * @version 2019/8/22 17:15
 */
public class ObjectUtils {
    private ObjectUtils() {
    }
    /**
     * 代理 class 的名称
     */
    private static final List<String> PROXY_CLASS_NAMES = Arrays.asList("net.sf.cglib.proxy.Factory"
            , "org.springframework.cglib.proxy.Factory"
            , "javassist.util.proxy.ProxyObject"
            , "org.apache.ibatis.javassist.util.proxy.ProxyObject");
    /**
     * 获取 type 的泛型，class 是无法获取泛型的
     *
     * @param type 类型
     * @return Type
     */
    public static Type[] getGeneric( Type type) {
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            return parameterizedType.getActualTypeArguments();
        }
        return null;
    }

    /**
     * 获取 type 的泛型，class 是无法获取泛型的
     *
     * @param type 类型
     * @return Type
     */
    public static Type getFirstGeneric(Type type) {
        return getFirstGeneric(getGeneric(type));
    }

    /**
     * 获取参数的泛型
     *
     * @param parameter 参数
     * @return Type
     */
    public static Type[] getGeneric(Parameter parameter) {
        Type type = parameter.getParameterizedType();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            return parameterizedType.getActualTypeArguments();
        }
        return null;
    }

    /**
     * 获取参数的泛型
     *
     * @param parameter 参数
     * @return Type
     */
    public static Type getFirstGeneric( Parameter parameter) {
        return getFirstGeneric(getGeneric(parameter));
    }

    /**
     * 获取字段的泛型
     *
     * @param field 对象字段
     * @return Type
     */
    public static Type[] getGeneric( Field field) {
        Type type = field.getGenericType();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            return parameterizedType.getActualTypeArguments();
        }
        return null;
    }

    /**
     * 获取字段的泛型
     *
     * @param field 对象字段
     * @return Type
     */
    public static Type getFirstGeneric( Field field) {
        return getFirstGeneric(getGeneric(field));
    }

    /**
     * 获取某个接口的泛型，
     * 例如：A类继承自List，List用到的泛型数Integer，业务中需要获取List采用的泛型。
     * 此时：instance填A.class, targetClass填写List.class
     *
     * @param instance    对象实例/接口
     * @param targetClass  目标接口
     * @return Type
     */
    public static Type[] getGeneric( Class<?> instance,  Class<?> targetClass) {
        Type[] superclass = instance.getGenericInterfaces();
        for (Type type : superclass) {
            if (type instanceof ParameterizedType) {
                ParameterizedType parameterized = (ParameterizedType) type;
                if (parameterized.getRawType().equals(targetClass)) {
                    return parameterized.getActualTypeArguments();
                }
            }
        }
        return null;
    }
    public static Type[] getParentGeneric( Class<?> instance,  Class<?> targetClass) {
        Type type = instance.getGenericSuperclass();
        if (type!=null && type instanceof ParameterizedType) {
            ParameterizedType parameterized = (ParameterizedType) type;
            if (parameterized.getRawType().equals(targetClass)) {
                return parameterized.getActualTypeArguments();
            }
            return getParentGeneric(type.getClass(),targetClass);
        }
        return null;
    }

    /**
     * 获取某个接口的泛型
     *
     * @param instance    对象实例/接口
     * @param targetClass 目标接口
     * @return Type
     */
    
    public static Type getFirstGeneric( Class<?> instance,  Class<?> targetClass) {
        return getFirstGeneric(getGeneric(instance, targetClass));
    }

    public static Type getByGenericByIndex( Class<?> instance,  Class<?> targetClass,Integer index) {
        Class<?> userClass = getUserClass(instance);
        Type[] type = getParentGeneric(userClass, targetClass);
        return getByGenericByIndex(type,index);
    }
    /**
     * <p>
     * 获取当前对象的 class
     * </p>
     *
     * @param clazz 传入
     * @return 如果是代理的class，返回父 class，否则返回自身
     */
    public static Class<?> getUserClass(Class<?> clazz) {
        return isProxy(clazz) ? clazz.getSuperclass() : clazz;
    }

    public static boolean isProxy(Class<?> clazz) {
        if (clazz != null) {
            for (Class<?> cls : clazz.getInterfaces()) {
                if (PROXY_CLASS_NAMES.contains(cls.getName())) {
                    return true;
                }
            }
        }
        return false;
    }
    public static Class<?> getByGenericClassByIndex( Class<?> instance,  Class<?> targetClass,Integer index) {
        return (Class<?>)getByGenericByIndex( instance,  targetClass, index);
    }


    public static Type getByGenericByIndex( Type[] types,Integer index) {
        if (CommonUtils.isNotEmpty(types)&& types.length>index) {
            return types[index];
        } else {
            return null;
        }
    }

    /**
     * 获取返回值泛型
     *
     * @param method -
     * @return type[]
     */
    
    public static Type[] getReturnGeneric( Method method) {
        Type type = method.getGenericReturnType();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            return parameterizedType.getActualTypeArguments();
        }
        return null;
    }

    /**
     * 获取返回值泛型
     *
     * @param method -
     * @return type[]
     */
    
    public static Type getFirstReturnGeneric( Method method) {
        return getFirstGeneric(getReturnGeneric(method));
    }

    /**
     * 多数场合下，并不需要返回全部的泛型类型
     *
     * @return 第一个泛型
     */
    
    public static Type getFirstGeneric( Type[] types) {
        if (CommonUtils.isNotEmpty(types)) {
            return types[0];
        } else {
            return null;
        }
    }



    /**
     * 获取非空集合的泛型
     *
     * @param c 非空集合
     */
    public static Class<?> getCollectionGeneric( Collection<?> c) {
        if (!c.isEmpty()) {
            return c.iterator().next().getClass();
        }
        return null;
    }

    /**
     * 获取非空数组的泛型
     *
     * @param o 非空数组
     */
    public static Class<?> getArrayGeneric( Object o) {
        int len = Array.getLength(o);
        if (len > 0) {
            return Array.get(o, 0).getClass();
        }
        return null;
    }


    /**
     * 遍历每一个对象元素
     *
     * @param o 可能是数组、集合、对象中的一种
     */
    public static void eachElement(Object o, Consumer<Object> consumer) {
        if (o != null) {
            Class<?> clazz = o.getClass();
            if (Map.class.isAssignableFrom(clazz)) {
                return;
            }
            if (Collection.class.isAssignableFrom(clazz)) {
                Collection<?> c = (Collection<?>) o;
                if (!c.isEmpty()) {
                    c.forEach(consumer);
                }
            } else if (clazz.isArray()) {
                // array
                int len = Array.getLength(o);
                if (len > 0) {
                    for (int i = 0; i < len; i++) {
                        consumer.accept(Array.get(o, i));
                    }
                }
            } else {
                consumer.accept(o);
            }
        }
    }

    /**
     * 遍历每一个对象元素
     *
     * @param o 可能是数组、集合、对象中的一种
     * @return 转换之后的元素
     */
    public static <R> Object applyEachElement(Object o, Function<Object, R> function) {
        if (o == null) {
            return null;
        }
        Class<?> clazz = o.getClass();
        if (Map.class.isAssignableFrom(clazz)) {
            return null;
        }
        if (Collection.class.isAssignableFrom(clazz)) {
            Collection<?> c = (Collection<?>) o;
            if (c.isEmpty()) {
                return Collections.emptyList();
            } else {
                return c.stream().map(function).collect(Collectors.toList());
            }
        } else if (clazz.isArray()) {
            // array
            int len = Array.getLength(o);
            Object[] ret = new Object[len];
            if (len > 0) {
                for (int i = 0; i < len; i++) {
                    ret[i] = function.apply(Array.get(o, i));
                }
            }
            return ret;
        } else {
            return function.apply(o);
        }
    }

    /**
     * 复制所有非空字段
     * <p>
     * 做数据更新的时候，先查询旧数据，将新的数据逐个复制到旧的数据中，在Hibernate下会非常实用
     *
     * @param source -
     * @param target -
     */
    public static <T> T copyField(Object source, T target) {
        FieldAccess from = FieldAccess.create(source.getClass());
        FieldAccess to = FieldAccess.create(target.getClass());
        for (ObjectField property : to.getFields()) {
            property.setValue(target, from.getValue(source, property.getName()));
        }
        return target;
    }

    /**
     * 创建一个对象实例
     *
     * @return instance
     */
    public static <T> T newInstance(Class<T> clazz) {
        try {
            return clazz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException("Create new instance failed：" + clazz, e);
        }
    }

    /**
     * 创建一个对象实例
     *
     * @return instance
     */
    public static Class<?> forName( String className) {
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("Class not found：" + className, e);
        }
    }
}
